/*******************************************************************************
*  Copyright 2013, Michael W. Eldridge                                         *
*  Under the terms of the GNU General Public License as published by           *
*  the Free Software Foundation, latest version.                               *
*                                                                              *
*******************************************************************************/

desc:MIDI Something v0.1

in_pin:none
out_pin:none

slider1:0<0,1,1{Bypassed,Active}>Status
slider64:0<0,1,1>PANIC !

@init     ///////////////////////////////////

TRUE = 1;
FALSE = 0;

function MIDIType()
(
    this.NoteOff        = $x80;
    this.NoteOn         = $x90;
    this.ControlChange  = $xB0; 
);

MIDIType.MIDIType();

function MIDIMessage()
(
    this.offset;
    this.type;
    this.channel;
    this.byte2;
    this.byte3;
);

message.MIDIMessage();

function getMIDIMessage()
(
    midirecv(offset, msg1, msg23) ? (
        message.offset   = offset;
        message.type     = msg1 & $xF0;
        message.channel  = msg1 & $x0F;
        message.byte2    = msg23 & $x7F;
        message.byte3    = msg23 >> 8;
        TRUE;
    );
);

function sendMIDIMessage(message)
(
    midisend(message.offset, message.type + message.channel,
      (message.byte2 | message.byte3 << 8));
);

function isNoteON(message)
(
    (message.type == MIDIType.NoteOn && message.byte3 > 0) ? (
        TRUE;
    ):(
        FALSE;
    );
);

function isNoteOFF(message)
(
    (message.type == MIDIType.NoteOff ||
     (message.type == MIDIType.NoteOn && message.byte3 == 0)) ? (
        TRUE;
    ):(
        FALSE;
    );
);

function isNote(message)
(
    isNoteON(message) || isNoteOFF(message) ? (
        TRUE;
    ):(
        FALSE;
    );
);

function isValid(x)
(
    (x >= 0) && (x <= 127) ? (
        TRUE;
    ):(
        FALSE;
    );
);

function sendAllNotesOff()
(
    i=0;
    loop ( 15,
        midisend(offset, MIDIType.ControlChange + i, $x7B | ($x00 << 8));
        i+=1;
    );
);

chord = 2000;
  memset(chord, 0, 128);

baseChord = 1000;
baseChord[1]  = $x000081;   //             1-5  //
baseChord[2]  = $x000085;   //           sus 2  // 
baseChord[3]  = $x000091;   //           Major  //
baseChord[4]  = $x0000B1;   //           add 4  //
baseChord[5]  = $x000291;   //           Maj 6  //
baseChord[6]  = $x004291;   //         Maj 6/9  //
baseChord[7]  = $x000891;   //           Maj 7  //
baseChord[8]  = $x004891;   //           Maj 9  //
baseChord[9]  = $x020891;   //          Maj 11  //
baseChord[10] = $x200891;   //          Maj 13  //

 
@slider   ///////////////////////////////////

isActive = slider1;
panic = slider64;

@block    ///////////////////////////////////

panic ? (
    sendAllNotesOff();
    panic = slider64 = 0;
    sliderchange(slider64);
);
 
while (
    getMIDIMessage() ? (     
        isNote(message) ? (
            isActive ? (
                isNoteON(message) ? (
                    root = message.byte2;
                    chord[root] = baseChord[(rand(10) | 0) + 1];
                    i = 0;
                    loop ( 24,
                        chord[root] & (2^i) ? (
                            message.byte2 = root + i;
                            isValid(message.byte2) ? (
                                sendMIDIMessage(message)
                            );
                        );
                        i += 1;
                    );    
                ):(
                    root = message.byte2;
                    i = 0;
                    loop ( 24,
                        chord[root] & (2^i) ? (
                            message.byte2 = root + i;
                            isValid(message.byte2) ? (
                                sendMIDIMessage(message)
                            );
                        );
                        i += 1;
                    );
                    chord[root] = 0;
                );
            ):(    // Pass through note if bypassed
                sendMIDIMessage(message)
            );
        ):(    // Pass through message if not a note event
            sendMIDIMessage(message)
        );
        1;    //  Continue
    );    //  End of getMIDIMessage() loop 
);    //  End of while loop
